#include <protocols/http/HTTP.hpp>

HTTP::HTTP()
{
  sock = 0;
  port = 80;
  proto_version = 1.1;
  http_server = "";
  headers_set = false;
  err = 0;
  response = 0;
  resp_received = false;
  resp_data = "";
  memset(&server_addr, 0, sizeof(server_addr));
}

HTTP::HTTP(string server, int port)
{
  sock = 0;
  this->port = port;
  proto_version = 1.1;
  http_server = server;
  headers_set = false;
  err = 0;
  response = 0;
  resp_received = false;
  resp_data = "";
  memset(&server_addr, 0, sizeof(server_addr));

  /* Eastablish connection as well. */
  sock = connect_to(server, port);

};

HTTP::HTTP(string server, int port, float proto)
{
  sock = 0;
  this->port = port;
  proto_version = proto;
  http_server = server;
  headers_set = false;
  err = 0;
  response = 0;
  resp_received = false;
  resp_data = "";
  memset(&server_addr, 0, sizeof(server_addr));

  /* Establish connection as well*/
  sock = connect_to(server, port);

};

HTTP::~HTTP()
{
  if( sock != 0) {
    close(sock);
    sock = 0;
  }

  memset(&server_addr, 0, sizeof(server_addr));
}

int HTTP::connect_to(string server, int port)
{
  char* ip = (char*) server.c_str();
  int sock_family = AF_INET;
  int sock_type = SOCK_STREAM;

  /* Create a socket. For HTTP, it will always by SOCK_STREAM. */
  sock = socket(sock_family, sock_type, 0);

  server_addr.sin_family = AF_INET;
  server_addr.sin_port = htons(port);
  inet_pton(AF_INET, ip, &server_addr.sin_addr);
  err = connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr));

 
  /* Connect returns -1 on error */
  if( err == -1) {
    err = errno;
    return -1;
  }
  
  return sock;
}

void HTTP::set_header(string field, string value)
{
  headers[field] = value;
  headers_set = true;
}

void HTTP::fetch(int method, string uri)
{
  string request = "";
  map<string, string>::iterator hdr;
  if(  method == GET ) {
    request += "GET ";
  } else if( method == POST ) {
    request += "POST";
  }

  if(uri.at(0) == '/') {
    uri = http_server + uri;
  }

  request += uri;

  if(proto_version == 1.1) {
    request += " HTTP/1.1\r\n";
  } else {
    request += " HTTP/1.1\r\n";
  }

  if(!headers_set && proto_version == 1.1) {
    request += "HOST: " + http_server + "\r\n";
  }

  if(headers_set) {
    for(hdr = headers.begin(); hdr != headers.end(); hdr++) {
      request += (*hdr).first + ": " + (*hdr).second + "\r\n";
    }
  }

  request += "\r\n";
  
  /* Send the data */
  send(sock, request.c_str(), request.length(), 0);
}

string HTTP::get_response(bool fetch_headers)
{
  char* buffer = (char*) malloc(1024);
  string data;
  fd_set http_sock;
  struct timeval t;
  int sel = 0;

  FD_ZERO(&http_sock);
  FD_SET(sock, &http_sock);

  t.tv_sec = 10;
  t.tv_usec = 0;

  while(1) {
    sel = select(sock+1, &http_sock, NULL, NULL, &t);
    if( sel == -1) {
      err = errno;
      return data;
    } else if(sel && FD_ISSET(sock, &http_sock)) {
      bytes = recv(sock, buffer, 1024, 0);
      data += buffer;
    } else {
      return data;
    }
  }
}
